package com.zhao.dota.security;

import com.zhao.dota.bo.AuthenticateUser;
import com.zhao.dota.model.Permission;
import com.zhao.dota.model.Role;
import com.zhao.dota.security.integration.IntegrationAuthentication;
import com.zhao.dota.security.integration.IntegrationAuthenticationContext;
import com.zhao.dota.security.integration.authenticator.IntegrationAuthenticator;
import com.zhao.dota.service.PermissionService;
import com.zhao.dota.service.RoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class UserDetailsServiceImpl implements UserDetailsService {

    private static final String ROLE_PREFIX = "ROLE_";

    private List<IntegrationAuthenticator> authenticators;

    @Resource
    private RoleService roleService;
    @Resource
    private PermissionService permissionService;

    @Autowired(required = false)
    public void setIntegrationAuthenticators(List<IntegrationAuthenticator> authenticators) {
        this.authenticators = authenticators;
    }

    @Override
    public AuthenticateUser loadUserByUsername(String username) throws UsernameNotFoundException {
        IntegrationAuthentication integrationAuthentication = IntegrationAuthenticationContext.get();
        //判断是否是集成登录
        if (integrationAuthentication == null) {
            integrationAuthentication = new IntegrationAuthentication();
        }
        integrationAuthentication.setUsername(username);
        AuthenticateUser authenticate = authenticate(integrationAuthentication);
        if (authenticate == null) {
            return null;
        }
        List<Role> roles = roleService.findByUserId(authenticate.getId());
        List<Permission> permissions = roles.stream().map(r -> permissionService.rolePermissions(r.getId()))
                .flatMap(Collection::stream)
                .collect(Collectors.toList());
        Stream<SimpleGrantedAuthority> roleStreams = roles.stream()
                .filter(r -> StringUtils.hasText(r.getCode()))
                .map(p -> new SimpleGrantedAuthority(ROLE_PREFIX + p.getCode()));

        List<Permission> menus = permissions.stream().filter(Permission::getMenu).distinct().collect(Collectors.toList());
        Stream<SimpleGrantedAuthority> permissionStream = permissions.stream().distinct().map(p -> new SimpleGrantedAuthority(p.getCode()));
        List<SimpleGrantedAuthority> grantedAuthorityList = Stream.concat(roleStreams, permissionStream).collect(Collectors.toList());
        authenticate.setAuthorities(grantedAuthorityList);
        authenticate.setMenus(menus);
        return authenticate;
    }


    private AuthenticateUser authenticate(IntegrationAuthentication integrationAuthentication) {
        if (this.authenticators != null) {
            for (IntegrationAuthenticator authenticator : authenticators) {
                if (authenticator.support(integrationAuthentication)) {
                    return authenticator.authenticate(integrationAuthentication);
                }
            }
        }
        return null;
    }


}
